﻿Imports Neslab.FIM.FIMUtils
Imports Microsoft.ResourceManagement.Workflow.Activities
Imports Microsoft.ResourceManagement.WebServices.WSResourceManagement

Public Class MakeAccountName
    Inherits SequenceActivity

#Region "Declarations"

    Private debug As New Debugging
    Private userID As Guid
    Private dictSearch As New Dictionary(Of String, String)
    Private accountName As String = Nothing
    Private _sqlLookup As Neslab.FIM.FIMUtils.sqlLookups

#End Region

#Region "Properties"

    Public Shared currentRequestActivity1_CurrentRequest1Property As System.Workflow.ComponentModel.DependencyProperty = DependencyProperty.Register("currentRequestActivity1_CurrentRequest1", GetType(Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType), GetType(Neslab.FIM.MakeAccountName))
    <System.ComponentModel.DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)> _
    <System.ComponentModel.BrowsableAttribute(True)> _
    <System.ComponentModel.CategoryAttribute("Misc")> _
    Public Property currentRequestActivity1_CurrentRequest1 As Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType
        Get
            Return CType(MyBase.GetValue(Neslab.FIM.MakeAccountName.currentRequestActivity1_CurrentRequest1Property), Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType)
        End Get
        Set(value As Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestType)
            MyBase.SetValue(Neslab.FIM.MakeAccountName.currentRequestActivity1_CurrentRequest1Property, value)
        End Set
    End Property

    Public Shared ActivityEnabledProperty As DependencyProperty = DependencyProperty.Register("ActivityEnabled", GetType(Boolean), GetType(MakeAccountName))
    <Description("ActivityEnabled")> <Category("ActivityEnabled Category")> <Browsable(True)> _
    <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    Public Property ActivityEnabled As Boolean
        Get
            Return (CType((MyBase.GetValue(MakeAccountName.ActivityEnabledProperty)), Boolean))
        End Get
        Set(ByVal Value As Boolean)
            MyBase.SetValue(MakeAccountName.ActivityEnabledProperty, Value)
        End Set
    End Property

    Public Shared stdNameProperty As DependencyProperty = DependencyProperty.Register("stdName", GetType(String), GetType(MakeAccountName))
    <Description("stdName")> <Category("stdName Category")> <Browsable(True)> <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    Public Property stdName() As String
        Get
            Return (CType((MyBase.GetValue(MakeAccountName.stdNameProperty)), String))
        End Get
        Set(ByVal Value As String)
            MyBase.SetValue(MakeAccountName.stdNameProperty, Value)
        End Set
    End Property

    Public Shared uniqueNameProperty As DependencyProperty = DependencyProperty.Register("uniqueName", GetType(String), GetType(MakeAccountName))
    <Description("uniqueName")> <Category("uniqueName Category")> <Browsable(True)> <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    Public Property uniqueName() As String
        Get
            Return (CType((MyBase.GetValue(MakeAccountName.uniqueNameProperty)), String))
        End Get
        Set(ByVal Value As String)
            MyBase.SetValue(MakeAccountName.uniqueNameProperty, Value)
        End Set
    End Property

    Public Shared exNameProperty As DependencyProperty = DependencyProperty.Register("exName", GetType(String), GetType(MakeAccountName))
    <Description("exName")> <Category("exName Category")> <Browsable(True)> <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    Public Property exName() As String
        Get
            Return (CType((MyBase.GetValue(MakeAccountName.exNameProperty)), String))
        End Get
        Set(ByVal Value As String)
            MyBase.SetValue(MakeAccountName.exNameProperty, Value)
        End Set
    End Property

    Public Shared exSearchProperty As DependencyProperty = DependencyProperty.Register("exSearch", GetType(String), GetType(MakeAccountName))
    <Description("exSearch")> <Category("exSearch Category")> <Browsable(True)> <DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
    Public Property exSearch() As String
        Get
            Return (CType((MyBase.GetValue(MakeAccountName.exSearchProperty)), String))
        End Get
        Set(ByVal Value As String)
            MyBase.SetValue(MakeAccountName.exSearchProperty, Value)
        End Set
    End Property

#End Region

#Region "Code Activities"

    Private Sub prepareToReadUser_ExecuteCode(sender As Object, e As EventArgs)

        'Get the containing workflow
        Dim containingWorkflow As SequentialWorkflow = Nothing
        If Not SequentialWorkflow.TryGetContainingWorkflow(Me, containingWorkflow) Then
            Throw New InvalidOperationException("Make Membership: unable to get Containing Workflow")
        End If

        'Prepare the properties for the readInputRecord activity
        readUser.ActorId = WellKnownGuids.FIMServiceAccount
        userID = containingWorkflow.TargetId
        readUser.ResourceId = userID

        debug.Log("read user has user with ObjectID = " & containingWorkflow.TargetId.ToString)

    End Sub

    Private Sub readUserResult_ExecuteCode(sender As Object, e As EventArgs)

        Dim displayName As String = readUser.Resource("DisplayName")

        debug.Log("Display Name is " & displayName)

        For Each attributeProperty As KeyValuePair(Of String, ResourcePropertyInfo) In readUser.Resource.ResourceProperties
            Dim attributeValue As String
            Dim val As Object = readUser.Resource(attributeProperty.Key)
            If val IsNot Nothing Then
                attributeValue = val.ToString()
                debug.Log(attributeProperty.Key & " " & attributeValue)
                dictSearch.Add(attributeProperty.Key, attributeValue)
            End If
        Next

    End Sub

    Private Sub makeUniqueAccountName_ExecuteCode(sender As Object, e As EventArgs)

        If ActivityEnabled Then

            'Make sense of the parameters
            'stdName - the name people should get if they aren't exceptions
            'uniqueName - the name people should get if the first name they get is not unique
            'exName - the name people should get if they are an exception
            'exSearch - the search criteria for exception

            '-----------------------Exception Checking ---------------------------
            Dim isException As Boolean = False

            'Ignore the first part of the XPATH for now
            Dim exSearchCriteria As String = exSearch.Split(New Char() {"[", "]"})(1)

            'Only allowable operator at the moment is "="
            'TODO: need to handle other operators
            Dim exSearchBits() As String
            exSearchBits = exSearchCriteria.Split("=")
            Dim exSearchAttr As String = exSearchBits(0)
            Dim exSearchValue As String = exSearchBits(1)

            'Look up the exception attribute value
            Dim attrVal As String = dictSearch.Item(exSearchAttr)
            If attrVal = exSearchValue Then
                isException = True
            End If

            '------------------Get the Name patterns:-------------------------------
            Dim separator As String = "&"
            'Standard pattern
            Dim stdNameBits As New ArrayList
            stdNameBits.AddRange(stdName.Split(separator))
            'Unique pattern
            Dim uniqueNameBits As New ArrayList
            uniqueNameBits.AddRange(uniqueName.Split(separator))
            'Exception pattern
            Dim exNameBits As New ArrayList
            exNameBits.AddRange(exName.Split(separator))

            '--------------------Create the Account Name-----------------------------
            If isException Then
                accountName = makeName(exNameBits)
            Else
                accountName = makeName(stdNameBits)
            End If

            '-------------------Check the Name is unique-----------------------------
            'For now, only a SQL lookup to the SV is supported
            'TODO: add AD and other lookup types and abstract this somemore - too tight at present

            _sqlLookup = New Neslab.FIM.FIMUtils.sqlLookups("Shadowverse")
            Dim available As Boolean = _sqlLookup.isUniqueInSV("AccountName", accountName)

            'Right now this doesn't supported returning people - for that we need an IsMe function

            '--------------------Create a unique name if not unique-------------------
            If Not available Then

                'Everyone gets the exception pattern if the first one fails
                accountName = makeName(uniqueNameBits)
                accountName = makeUniqueName(accountName)

            End If

            _sqlLookup.Close()

        End If

    End Sub

    Private Sub prepareToUpdateUser_ExecuteCode(sender As Object, e As EventArgs)

        updateUser.ActorId = WellKnownGuids.FIMServiceAccount
        updateUser.ResourceId = userID

        Dim updateRequestParameters As New List(Of UpdateRequestParameter)
        updateRequestParameters.Add(New UpdateRequestParameter("AccountName", UpdateMode.Modify, accountName))
        updateUser.UpdateParameters = updateRequestParameters.ToArray()

    End Sub

#End Region

#Region "Utility Functions"

    Public Function makeName(ByVal list As ArrayList) As String

        Dim returnVal As String = Nothing
        Dim nameParts As List(Of String) = New List(Of String)
        Dim dot As String = "."

        For Each element As String In list
            If element = dot Then
                nameParts.Add(element)
            ElseIf element.Contains("(") Then
                'This is an attribute with a substring e.g. givenName(1)
                'Need to find the attribute value and trim it to the right length
                Dim brIndex = element.IndexOf("(")
                Dim subStr As String = Convert.ToInt32(element.ToString.Substring(brIndex + 1).Trim(")"))
                Dim attr As String = element.Remove(brIndex)
                Dim attrVal As String = dictSearch.Item(attr)
                nameParts.Add(attrVal.Remove(subStr))
            ElseIf element = "#" Then
                'This is the incrementor, just add and let the higher up code deal with it
                nameParts.Add(element)
            Else
                'Not a dot or a substring, just find the value and add
                nameParts.Add(dictSearch.Item(element))
            End If
        Next

        For Each part As String In nameParts
            returnVal = returnVal & part
        Next

        Return returnVal

    End Function

    Public Function makeUniqueName(ByVal accountName As String) As String
        'This function assumes it is getting an alias with a # in it to use as the point to increment

        Dim returnVal As String = Nothing
        Dim available As Boolean = False

        For i As Integer = 1 To Integer.MaxValue
            '# is the incrementing integer
            accountName = accountName.Replace("#", i)
            available = _sqlLookup.isUniqueInSV("AccountName", accountName)
            If available Then
                Exit For
            End If
            accountName = (accountName.Replace(i, "#"))
        Next
        returnVal = accountName
        Return returnVal

    End Function

#End Region


End Class
